package com.atguigu.gmall.seckill.api;

import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.feign.order.OrderFeignClient;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.mq.MqConst;
import com.atguigu.gmall.seckill.component.SecKillLocalCache;
import com.atguigu.gmall.seckill.mq.to.SeckillSuccessTo;
import com.atguigu.gmall.seckill.service.SecKillService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

@RequestMapping("/api/activity/seckill")
@RestController
public class SecKillApiController {

    @Autowired
    SecKillService secKillService;
    @Autowired
    SecKillLocalCache localCache;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    OrderFeignClient orderFeignClient;
    @Autowired
    StringRedisTemplate redisTemplate;

    /*
     * 生成秒杀码
     * */
    @GetMapping("/auth/getSeckillSkuIdStr/{skuId}")
    public Result getSecKIllCode(@PathVariable("skuId") Long skuId, HttpServletRequest request) {
        String userId = AuthContextHolder.getUserId(request);
        //生成秒杀码  MD5(skuId+用户id)
        String code = secKillService.generateSeckillCode(skuId, userId);
        if ("error".equals(code)) {
            return Result.build(null, ResultCodeEnum.SECKILL_NO_START);
        }
        return Result.ok(code);
    }

    /**
     * 秒杀下单方法，决定是否能秒成功
     * 1、
     * /api/activity/seckill/auth/seckillOrder/46?skuIdStr=秒杀码,
     *
     * @param skuIdStr
     * @param skuId
     * @return
     */
    @PostMapping("/auth/seckillOrder/{skuId}")
    public Result seckillOrder(@RequestParam("skuIdStr") String skuIdStr,
                               @PathVariable("skuId") Long skuId,
                               HttpServletRequest request) {
        //合法性校验
        //1、校验秒杀码是否正确
        String userId = AuthContextHolder.getUserId(request);
        Boolean code = secKillService.checkSeckillCode(skuId, userId, skuIdStr);
        if (!code) {
            //秒杀码错误
            return Result.build(null, ResultCodeEnum.SECKILL_ILLEGAL);
        }

        //2、校验状态位，先不去校验信号量。先去校验内存状态位（延迟更新，redis真的没了，他才会更新没有）
        //我说没，一定没，我说有，不一定有
        SeckillGoods goods = localCache.getSeckillGoodsBySkuId(skuId);
        if ((goods.getNum() - goods.getStockCount()) <= 0) {
            //内存状态位都没有了
            return Result.build(null, ResultCodeEnum.SECKILL_FINISH);
        }

        //3、接下来确认下，这个人是否已经下了这个秒杀单？   SECKILL_ORDER_SUCCESS(218, "下单成功"),
        // 未来，只要抢购成功，我们会给redis中预保存这个人的秒杀单信息。查redis
        if (!secKillService.checkRepeat(skuId, userId, skuIdStr)) {
            //只做一次。如果是重复的。有可能这个人已经发过请求，只需要返回ok。前端每3秒检查订单状态
            return Result.ok();
        }
        ;

        //4、快速扣库存。获取信号量
        boolean b = secKillService.seckillStockLocked(skuId, userId, skuIdStr);
        if (!b) {
            return Result.build(null, ResultCodeEnum.SECKILL_FINISH);
        }

        //秒杀成功.SECKILL_SUCCESS(215, "抢单成功");
        //扣库存成功，预示着秒杀成功，给mq发消息，说哪个用户。秒杀哪个商品成了
        rabbitTemplate.convertAndSend(MqConst.SECKILL_EXCHANGE,
                MqConst.SECKILL_SUCCESS_RK,
                new SeckillSuccessTo(userId, skuId, skuIdStr));

        //成功返回ok
        return Result.ok();
    }

    /**
     * 检查订单
     * url: this.api_name + '/auth/checkOrder/' + skuId,
     *
     * @return
     */
    @GetMapping("/auth/checkOrder/{skuId}")
    public Result checkSeckillOrder(@PathVariable("skuId") Long skuId, HttpServletRequest request) throws JsonProcessingException {
        //1、211: 正在排队中  ResultCodeEnum.SECKILL_RUN                    this.show = 1 ：正在排队
        //   215：抢单成功：   ResultCodeEnum.SECKILL_SUCCESS               this.show = 3 : 去订单确认页
        //   218：下单成功：  ResultCodeEnum.SECKILL_ORDER_SUCCESS          this.show = 4 : 已经下单了(订单确认信息也有了)，去订单页看

        //  其他情况、
        String userId = AuthContextHolder.getUserId(request);
        ResultCodeEnum status = secKillService.checkOrderStatus(skuId, userId);
        return Result.build(null, status);
    }

    /**
     * 秒杀订单完全信息提交
     *
     * @param orderInfo
     * @return
     * @throws JsonProcessingException
     */
    @PostMapping("/auth/submitOrder")
    public Result submitOrder(@RequestBody OrderInfo orderInfo, HttpServletRequest request) throws JsonProcessingException {
        String userId = AuthContextHolder.getUserId(request);
        //提交秒杀单,设置好用户id
        orderInfo.setUserId(Long.parseLong(userId));

        //给订单服务
        OrderInfo info = orderFeignClient.submitSeckillOrder(orderInfo);

        //重新给redis中存一份。方便状态检查。
//        redisTemplate
        String json = new ObjectMapper().writeValueAsString(info);
        redisTemplate.opsForValue().set(RedisConst.SECKILL_USER+info.getUserId(),json);

        return Result.ok(info.getId());
    }
}
